package org.tech4j.edi.base.executor;

import com.google.common.collect.Maps;
import org.tech4j.common.concurrent.timer.AbstractRetryTask;
import org.tech4j.common.concurrent.timer.Timer;
import org.tech4j.common.concurrent.timer.TimerTask;
import org.tech4j.common.concurrent.timer.WheelTimerFactory;
import org.tech4j.edi.api.RetryExecutor;
import org.tech4j.edi.api.RetryExecutorChain;
import org.tech4j.edi.base.threadpool.RetryThreadPoolFactory;
import org.tech4j.edi.common.entity.RetryBizConfig;
import org.tech4j.edi.api.context.RetryContext;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: tech4j
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/7 16:22
 **/
public class DynamicThreadPoolRetryExecutor implements RetryExecutor {

    private volatile Timer timer;
    private final ConcurrentMap<String, AtomicInteger> retrySlowCountMap = Maps.newConcurrentMap();

    @Override
    public void execute(RetryContext retryContext, RetryExecutorChain chain) {
        initTimer();
        ThreadPoolExecutor threadPoolExecutor = select(retryContext.getRetryBizConfig());
        retryContext.setExecutorService(threadPoolExecutor);
        retryContext.setRetrySlowCountMap(retrySlowCountMap);
        chain.execute(retryContext);
    }

    @Override
    public int getOrder() {
        return EdiExecutorsOrder.SELECT_DYNAMIC_THREAD_POOL.getOrder();
    }

    private void initTimer() {
        if (timer == null) {
            timer = WheelTimerFactory.getSharedTimer();
            timer.add(new DynamicRetryTask("DynamicThreadPoolRetry", retrySlowCountMap));
        }
    }

    /**
     * 动态选择线程池
     *
     * 如果当前业务类型的处理时间超时次数超过阈值, 则设置为慢线程池处理
     *
     * @param config
     * @return
     */
    private ThreadPoolExecutor select(RetryBizConfig config) {
        AtomicInteger retrySlowCount = retrySlowCountMap.getOrDefault(config.getBizType(), new AtomicInteger(0));
        if (retrySlowCount.get() > config.getHourOverTimes()) {
            return RetryThreadPoolFactory.retrySlowThreadPool;
        } else {
            return RetryThreadPoolFactory.retryFastThreadPool;
        }
    }

    private static final class DynamicRetryTask extends AbstractRetryTask {
        private final ConcurrentMap<String, AtomicInteger> retrySlowCountMap;
        public DynamicRetryTask(final String key, ConcurrentMap<String, AtomicInteger> retrySlowCountMap) {
            super(key, 1200000, -1);
            this.retrySlowCountMap = retrySlowCountMap;
        }

        @Override
        protected void doRetry(String key, TimerTask timerTask) {
            retrySlowCountMap.clear();
        }
    }
}
